﻿using amuudp.package;
using fenping.package;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace amuudp
{
    class Program
    {
        static UdpServer client;

        static void Main(string[] args)
        {
            Console.Write("客户端唯一ID:");
            string clientId = Console.ReadLine();
            Console.Write("客户端端口号:");
            string clientPort = Console.ReadLine();
            Console.Write("客户端名称:");
            string clientName = Console.ReadLine();

            ServerEvents serverEvents = new ServerEvents(
                clientId.Trim() == "" ? new Random().Next() : int.Parse(clientId),
                clientPort.Trim() == "" ? 8112 : int.Parse(clientPort));

            serverEvents.ClientName = clientName;
            
            while(true)
            {
                Console.Write(">");
                string command = Console.ReadLine();
                UdpInfo info = new UdpInfo(command, ':', '=', ' ');
                if (info.Type == "connect")
                {
                    string serverIp = info.Get(0);
                    string serverPort = info.Get(1);
                    serverEvents.Connect(serverIp, int.Parse(serverPort));
                }
                else if(info.Type == "setting")
                {
                    if (info.Has("framerate")) serverEvents.FrameRate = int.Parse(info.Get("framerate"));
                }
                else if(info.Type == "quit")
                {
                    break;
                }
            }

            serverEvents.Stop();
            Console.WriteLine("感谢使用，再见！");
            Thread.Sleep(1000);

            return;
        }
    }


    class ServerEvents : IServerEvents
    {
        public UdpServer client;
        private Thread captureThread;
        private int imageId = 0;

        public string ServerIp = "127.0.0.1";
        public int ServerPort = 0;
        public int ClientId = 0;
        public int ClientPort = 0;
        public string ClientName = "未命名";
        public int FrameRate = 16; // 帧速率

        // 以下属性受服务器控制
        int NeededFrameRate = 24; // 服务器需要的最大帧速率
        int NeededWidth = 1920; // 服务器需要的最大宽度
        int NeededHeight = 1080; // 服务器需要的最大高度
        int ShouldCapture = 0; // 是否需要截图
        int ShouldCompress = 0; // 是否需要压缩

        private IPEndPoint ServerAP
        {
            get
            {
                return new System.Net.IPEndPoint(IPAddress.Parse(ServerIp), ServerPort);
            }
        }

        public ServerEvents(int clientId, int clientPort)
        {
            ClientId = clientId;
            ClientPort = clientPort;
            client = new UdpServer(clientId, clientPort, this);
            client.Start();
        }


        public void OnPackageComplete(Package package, IPAddress ip, int port, params Object[] args)
        {
            if (package.Type == PackageType.Message)
            {
                MessagePackage messagePackage = new MessagePackage(package);

                Console.WriteLine(messagePackage.Message);

                UdpInfo info = new UdpInfo(messagePackage.Message);
                InfoRun(info, ip);
            }
            else
            {
                Console.WriteLine($"非消息类型，客户端编号：{package.ClientId}，包ID：{package.Id}，包大小：{package.Size}, 包类型：{package.Type}");
            }
        }

        private void InfoRun(UdpInfo info, IPAddress ip)
        {
            if (info.Type == "connect")
            {
                ServerPort = int.Parse(info.Get("port"));
                ServerIp = ip.ToString();
                // 收到客户端的连接，先确保客户端的信息都发送到服务器，然后再传截图
                Connect(ServerIp, ServerPort);
            }
            else if(info.Type == "connected")
            {
                //BeginCapture();
            }
            else if(info.Type == "stop")
            {
                StopCapture();
            }
            else if(info.Type == "capture")
            {
                BeginCapture();
            }
            else if(info.Type == "setting")
            {
                if(info.Has("framerate")) FrameRate = int.Parse(info.Get("framerate"));
                if (info.Has("width")) NeededWidth = int.Parse(info.Get("width"));
                if (info.Has("height")) NeededHeight = int.Parse(info.Get("height"));
            }
        }

        public void Connect(string ip, int port)
        {
            ServerIp = ip;
            ServerPort = port;

            UdpInfo info = new UdpInfo("connect");
            info.Add("port", ClientPort.ToString());
            info.Add("clientid", ClientId.ToString());
            info.Add("clientname", ClientName);
            client.Send(info.ToString(), ServerAP);
        }

        public void Disconnect()
        {
            UdpInfo info = new UdpInfo("disconnect");
            info.Add("clientid", ClientId.ToString());
            client.Send(info.ToString(), ServerAP);
        }

        private void BeginCapture()
        {
            ShouldCapture = 1;

            if(captureThread != null)
            {
                captureThread.Abort();
            }
            captureThread = new Thread(() => CaptureDo());
            captureThread.Start();
        }

        private void StopCapture()
        {
            ShouldCapture = 0;

            Thread.Sleep(500);

            if(captureThread != null)
            {
                captureThread.Abort();
            }
        }

        private void CaptureDo()
        {
            int lastedImageByteSize = 0;

            while(ShouldCapture == 1)
            {
                Bitmap bitmap = CaptureScreen.Capture(1920, 1080);
                bitmap = CaptureScreen.Compress(bitmap, NeededWidth, NeededHeight);

                byte[] imageBytes;
                using (MemoryStream stream = new MemoryStream())
                {
                    bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
                    imageBytes = new byte[stream.Length];
                    stream.Seek(0, SeekOrigin.Begin);
                    stream.Read(imageBytes, 0, Convert.ToInt32(stream.Length));
                }

                if (lastedImageByteSize != imageBytes.Length)
                {
                    client.Send(imageBytes, imageId++, ServerAP);
                    lastedImageByteSize = imageBytes.Length;
                }
                Thread.Sleep(1000 / Math.Min(FrameRate, NeededFrameRate));
            }
        }

        public void OnReceive(Fragment fragment, IPAddress ip, int port, params object[] args)
        {
            //Console.WriteLine($"{fragment.Index}");
        }

        public void Stop()
        {
            Disconnect();

            StopCapture();
            client.Stop();
        }
    }

    
}
